-
Notifications
You must be signed in to change notification settings - Fork 650
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add nodeRef
alternative instead of internal findDOMNode
#559
Conversation
ref
instead of findDOMNode
ref
instead of findDOMNode
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't this going to break stuff when rendering functional children that can't accept refs?
@taion I'll add some tests with different types of components, and see whats happening.
They mean that cannot use it inside a function component. |
Any ideas on when (and if) this will be merged? |
The way I understand this PR, I would say it is going to break things. Whatever you want to transition would have to either accept a ref (a forwardRef component), or be a plain dom element. Or am I missing something? It's happened before, many times... :) |
@einarq you are absolutely right. Whatever you want to transition would have to resolve to a DOM ref. So this would be a breaking change. @taion what are your thoughts on creating a new major version, using |
+1 for a new major version |
Or I'll try to find a solution that will |
Hi, there :) I see that these changes lead to the fact that I need to wrap my component to What about provide this:
If user provide I can create PR. |
@inomdzhon I also thought of this, user should pas to function App() {
const ref = React.useRef()
return (
<Transition domRef={ref}>
<MaybeDOMmaybeFunctionMaybeClass refThatComponentAccepts={ref} />
</Transition>
)
} Using the method above, we can make it non breaking change, and use I am also thinking of writing a experimental hook. Maybe something like this function App() {
const ref = React.useRef()
useTransition(ref)
return (
<MaybeDOMmaybeFunctionMaybeClass refThatComponentAccepts={ref} />
)
} |
Hm, but what about list of component?
It can be hard to collect all refs and provide to May be we can use render props (like
|
@inomdzhon in this case we can have this maybe? function App() {
return (
<TransitionGroup>
<CSSTransition domRef="hostRef"><div>1</div></CSSTransition>
<CSSTransition domRef="hostRef"><div>2</div></CSSTransition>
<CSSTransition domRef="hostRef"><div>3</div></CSSTransition>
</TransitionGroup>
);
} or even better this function App() {
return (
<TransitionGroup domRef="hostRef">
<CSSTransition><div>1</div></CSSTransition>
<CSSTransition><div>2</div></CSSTransition>
<CSSTransition><div>3</div></CSSTransition>
</TransitionGroup>
);
} And |
I think For don't repeat users can customize
Than
|
This are all use cases I can see for the API right now. import React from 'react'
import { Transition, TransitionGroup } from 'react-transition-group'
function MaybeDomOrFunctionOrClass(props) {
const { refThatResolvesToDOM } = props
return <div ref={refThatResolvesToDOM}>666</div>
}
function App() {
const ref = React.useRef(null)
const ref1 = React.useRef(null)
const ref2 = React.useRef(null)
const ref3 = React.useRef(null)
return (
<React.Fragment>
/* it will use ref to make transition */
<Transition domRef={ref}>
<MaybeDomOrFunctionOrClass refThatResolvesToDOM={ref} />
</Transition>
/* it will try to find and use prop `refThatResolvesToDOM` */
/* otherwise fallback to `findDOMNode` */
<Transition domRef="refThatResolvesToDOM">
<MaybeDomOrFunctionOrClass refThatResolvesToDOM={ref} />
</Transition>
/* it will try to find and use prop `refThatResolvesToDOM` */
/* otherwise fallback to `findDOMNode` */
/* ??? maybe create a ref internally in Transition and pass as `refThatResolvesToDOM` to child */
<Transition domRef="refThatResolvesToDOM">
<MaybeDomOrFunctionOrClass />
</Transition>
<TransitionGroup>
<Transition domRef={ref1}>
<MaybeDomOrFunctionOrClass refThatResolvesToDOM={ref1} />
</Transition>
<Transition domRef={ref2}>
<MaybeDomOrFunctionOrClass refThatResolvesToDOM={ref2} />
</Transition>
<Transition domRef={ref3}>
<MaybeDomOrFunctionOrClass refThatResolvesToDOM={ref3} />
</Transition>
</TransitionGroup>
<TransitionGroup>
<Transition domRef="refThatResolvesToDOM">
<MaybeDomOrFunctionOrClass refThatResolvesToDOM={ref1} />
</Transition>
<Transition domRef="refThatResolvesToDOM">
<MaybeDomOrFunctionOrClass refThatResolvesToDOM={ref2} />
</Transition>
<Transition domRef="refThatResolvesToDOM">
<MaybeDomOrFunctionOrClass refThatResolvesToDOM={ref3} />
</Transition>
</TransitionGroup>
<TransitionGroup>
<Transition domRef="refThatResolvesToDOM">
<MaybeDomOrFunctionOrClass />
</Transition>
<Transition domRef="refThatResolvesToDOM">
<MaybeDomOrFunctionOrClass />
</Transition>
<Transition domRef="refThatResolvesToDOM">
<MaybeDomOrFunctionOrClass />
</Transition>
</TransitionGroup>
<TransitionGroup domRef="refThatResolvesToDOM">
<Transition>
<MaybeDomOrFunctionOrClass />
</Transition>
<Transition>
<MaybeDomOrFunctionOrClass />
</Transition>
<Transition>
<MaybeDomOrFunctionOrClass />
</Transition>
</TransitionGroup>
</React.Fragment>
)
} |
Ok, I see. What about use The fewer use cases, the easier it is to use and maintain code. Over the years, I realized that the principle the easier the better. I mean we shouldn't complicate. |
Hey, |
Any updates on release schedule? |
Hi, @iamandrewluca 👋 How I can help you? |
ref
instead of findDOMNode
ref
instead of findDOMNode
Still thinking how to provide the API for the end user. The limitation of creating the ref internally is that we don't know what kind of children the |
If taking the example above from #559 (comment) And changing function MaybeDomOrFunctionOrClass(props) {
const { refThatResolvesToDOM } = props
return <div ref={refThatResolvesToDOM}>666</div>
} to function MaybeDomOrFunctionOrClass() {
const ref = React.useRef(null)
return (
<Transition domRef={ref}>
<div ref={ref}>666</div>
</Transition>
)
} then our function App() {
return (
<React.Fragment>
<MaybeDomOrFunctionOrClass />
<TransitionGroup>
<MaybeDomOrFunctionOrClass />
<MaybeDomOrFunctionOrClass />
<MaybeDomOrFunctionOrClass />
</TransitionGroup>
</React.Fragment>
)
} |
If function MaybeDomOrFunctionOrClass({ innerRef = React.useRef(null) }) {
return (
<Transition domRef={innerRef}>
<div ref={innerRef}>666</div>
</Transition>
)
} function App() {
const ref = React.useRef(null)
const ref1 = React.useRef(null)
const ref2 = React.useRef(null)
const ref3 = React.useRef(null)
return (
<React.Fragment>
<MaybeDomOrFunctionOrClass innerRef={ref} />
<TransitionGroup>
<MaybeDomOrFunctionOrClass innerRef={ref1} />
<MaybeDomOrFunctionOrClass innerRef={ref2} />
<MaybeDomOrFunctionOrClass innerRef={ref3} />
</TransitionGroup>
</React.Fragment>
)
} |
ref
instead of findDOMNode
domRef
alternative instead of findDOMNode
I'll do some tests using this PR and reactstrap components. |
Yeah, I understood 👌Waiting tests. Furthermore, I realized on this point |
domRef
alternative instead of findDOMNode
domRef
alternative instead of findDOMNode
# [4.4.0](v4.3.0...v4.4.0) (2020-05-05) ### Features * add `nodeRef` alternative instead of internal `findDOMNode` ([#559](#559)) ([85016bf](85016bf))
🎉 This PR is included in version 4.4.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
I didn't realize we have semantic-release set up 😅 I'll update release notes and the documentation. |
Guys, thank you so much for all the work you did for addressing this issue. Also, migrating my library to the new api was a breeze. 🙏 |
I'm glad that you're already enjoying the update! ❤️ Let us know if there are any issues. |
I feel like the typing of nodeRef should be extended. Right now it only accommodates for the type 'Element' which is limiting in case of nested routes. Please, let me know if I misunderstood #559.
Here's my situation: Level 1 router is a <Switch> handling switching between high-level website sections which, themselves are routers handling level 2 navigation (<Switch>'es). Right now, I'm drilling nodeRef down to div's through nested <Switch>'es and it: a) feels hacky, b) interferes with level 2 CSSTransitions. Am I missing something? Is the only way around this to wrap all of my <Switch>'es in <div ref={nodeRef}>'s? |
@antikvarBE can you provide a simple example? I kind of understand what are you trying to do, and I think I know what should you do, but I don't see entire picture. |
Thanks for reaching back @iamandrewluca . In Private.tsx const nodeRef = React.useRef(null);
return (
<div id={'private'} className={styles.wrapper}>
<MainMenu items={items} />
<main className={styles.content}>
<SwitchTransition mode={'out-in'}>
<CSSTransition
key={location.pathname.split('/', 3).join('/')}
timeout={500}
classNames={{ ...styles }}
nodeRef={nodeRef}
>
<PrivateRouter location={location} ref={nodeRef} />
</CSSTransition>
</SwitchTransition>
</main>
</div>
); In PrivateRouter.routes.tsx const PrivateRouter: React.FC<SwitchProps & {nodeRef: React.MutableRefObject<null>}> = ({ location }) => (
<Switch location={location} ref={nodeRef}>
<Route path={'/favorites'}>
<Favorites />
</Route>
<Route path={'/support'}>
<Support />
</Route>
<Route path={'/account'}>
<Account />
</Route>
</Switch>
); Doing this would throw the aforementioned error:
So, currently, I'm doing this instead: const nodeRef = React.useRef(null);
return (
<div id={'private'} className={styles.wrapper}>
<MainMenu items={items} />
<main className={styles.content}>
<SwitchTransition mode={'out-in'}>
<CSSTransition
key={location.pathname.split('/', 3).join('/')}
timeout={500}
classNames={{ ...styles }}
nodeRef={nodeRef}
>
<div ref={nodeRef}> // <-- This is my current workaround
<PrivateRouter location={location} />
</div>
</CSSTransition>
</SwitchTransition>
</main>
</div>
); It works perfectly fine but I'm the kind of person who thinks twice before introducing another DOM level and if I can get away without doing it and keep things nice and clean semantically, I'd rather do that. What do you think? |
Is |
@silvenon , it's from react-router-dom. (JSX attribute) React.ClassAttributes<Switch>.ref?: string | ((instance: Switch | null) => void) | React.RefObject<Switch> | null | undefined |
Oh, then |
@antikvarBE in example above if I'm not mistaken you want to transition between private routes? What version of react router do you use? |
@iamandrewluca , I'm using "react-router": "^5.2.0" and "react-router-dom": "^5.2.0". Yes, I'm transitioning between private routes as they're described in Private.routes.tsx (see example). Essencially, <Switch> displays one and only one <Route> at a time. If one route only contains one component, it also means <Switch> displays one and only one component at a time. That's the way I understand it. |
@silvenon : Got it. That makes sense. Just wanted to double-check. Thanks a bunch. |
# [4.4.0](reactjs/react-transition-group@v4.3.0...v4.4.0) (2020-05-05) ### Features * add `nodeRef` alternative instead of internal `findDOMNode` ([#559](reactjs/react-transition-group#559)) ([85016bf](reactjs/react-transition-group@85016bf))
# [4.4.0](reactjs/react-transition-group@v4.3.0...v4.4.0) (2020-05-05) ### Features * add `nodeRef` alternative instead of internal `findDOMNode` ([#559](reactjs/react-transition-group#559)) ([85016bf](reactjs/react-transition-group@85016bf))
# [4.4.0](reactjs/react-transition-group@v4.3.0...v4.4.0) (2020-05-05) ### Features * add `nodeRef` alternative instead of internal `findDOMNode` ([#559](reactjs/react-transition-group#559)) ([85016bf](reactjs/react-transition-group@85016bf))
# [4.4.0](reactjs/react-transition-group@v4.3.0...v4.4.0) (2020-05-05) ### Features * add `nodeRef` alternative instead of internal `findDOMNode` ([#559](reactjs/react-transition-group#559)) ([85016bf](reactjs/react-transition-group@85016bf))
RFC: An alternative to ReactDOM.findDOMNode
nodeRef
alternative for internalfindDOMNode
We can name prop one of this:
domRef
nodeRef
✓guestRef
transitionRef
ref
(withforwardRef
but BREAKING CHANGE)PRs:
Closes #457
Closes #486
Closes #514
Issues:
Closes #287
Closes #429